#include "auxiliar.h"

void failOpeningFile(string filename, int line, const char* cppfile){
	char msg[256]; sprintf(msg,"File '%s' could not be opened or do not exist.\n ",filename.c_str());
	throw Exception(line,cppfile,msg);
}

// multiply a tensor K by a vector vec
void multTensorVector2D(const double *tensor, const double *vec, double *mult){
	mult[0] = tensor[0]*vec[0]+tensor[1]*vec[1];
	mult[1] = tensor[2]*vec[0]+tensor[3]*vec[1];
}

// converts a string read from file to a double
double strToDouble(string &str){
	return strtod(getSubString(str), 0);
}

// converts a string read from file to an interger
int strToInteger(string &str){
	return atoi(getSubString(str));
}

// filters string the numeric part - internal use
const char* getSubString(string &str){
	string::size_type loc = str.find( "=", 0 );
	string numberstr = str.substr(loc+1, str.size()-loc);
	return numberstr.c_str();
}

// Make a vector given to nodes
void makeVector(const double *A, const double *B, double *v){
	for (int i=0; i<3; i++) v[i] = B[i] - A[i];
}

bool isEdgeExternal(int flag){
	return ( flag>=1000 && flag<=1499 );
}

bool isEdgeInternal(int flag){
	return ( flag>=1500 && flag<=1999 );
}

bool isFaceExternal(int flag){
	return ( flag>=2000 && flag<=2499 );
}

bool isFaceInternal(int flag){
	return ( flag>=2500 && flag<=2999 );
}


double* getIdentityMatrix(const int &dim){
	int i,j,k = 0;
	double *Identity = new double[dim*dim];
	for (i=0; i<dim; i++)
		for (j=0; j<dim; j++)
			Identity[k++] = (i==j)?1.0:.0;
	return Identity;
}

void replaceAllOccurencesOnString(string &theString, string::size_type size,
		string seekFor, string replaceFor){
	string::size_type pos = 0;
	while (true){
		pos = theString.find(seekFor,pos);
		if (pos != string::npos)
			theString.replace(pos,size,replaceFor);
		else
			break;
	}
}

void E_IJvector(double *I, double *J, double *IJ){
	for (int i=0; i<3; i++) IJ[i] = J[i]-I[i];
}

void printSimulationHeader(){
	//if (!0)
	std::cout<< "\n\n\t\t\t###################################################################\n"
			"\t\t\t\t\tUNIVERSIDADE FEDERAL DE PERNAMBUCO\n"
			"\t\t\t\t\tPADMEC - DECIV - DEMEC - PRH-26 - CNPq\n"
			"\t\t\t\t\t\t\t2008-2010\n"
			"\n\t\t\t\t\tParallel Reservoir Simulator - v1.1.5\n"
			"\t\t\t\t\tAuthor: Silva, R. S.\n"
			"\t\t\t\t\tNO WARRANTY!!! \n"
			"\t\t\t\t\tUSE IT AT YOUR OWN RISK!!!\n"
			"\t\t\t###################################################################\n\n";
}

void convertSecToTime(double t, double *h, double *m, double *s){
	double frac;
	frac = modf(t/3600.,h);
	frac = modf(frac*60.,m);
	frac = modf(frac*60.,s);
}


void LogFiles(LOG_FILES LG, double t1, double t2, double timeStep, double accSimTime,
		string path, bool hasRestart, int last_step, double CPU_time){

	static int count = 0;//(hasRestart)?last_step:0;
	static double acc_CPUtime = 0;//(hasRestart)?CPU_time:0;
	static ofstream fid1;
	static ofstream fid2;

	switch (LG){
	case OPENLG:{
		// print results on file
		//		if (!0){
		char fname1[256]; sprintf(fname1,"%s_simulation-monitor-%d.dat",path.c_str(),1);
		if (hasRestart){
			fid1.open(fname1,ios_base::app);
			fid1 << "* * * * * * * * * * * * * * * * * * * * * * * * *\n"
					"*                Restart required               *\n"
					"* * * * * * * * * * * * * * * * * * * * * * * * *\n\n\n";
		}
		else{
			fid1.open(fname1);
			fid1 << "SIMULATION PROGRESS MONITOR\nNumber of processors: "<<1<<"\n\n\n";
		}
		//	cout << __LINE__ << endl;
		char fname2[256]; sprintf(fname2,"%s_CPU-process-time-%d.xls",path.c_str(),1);
		fid2.open(fname2);
		fid2 << "Elliptic Hyperbolic total-step Total(accumulated)\n";
		//	cout << __LINE__ << endl;
		std::cout << "\n--------------------------------------------------\n"
				"Start Simulation\n"
				"--------------------------------------------------\n\n";
		//}
	}
	break;
	case UPDATELG:{
		// take average time from all processors
		// todo: implememt to parallel
		double total = t1+t2; //P_getSumDbl(t1+t2)/((double)1);

		// rank 0 is in charge to print the output CPU-time
		//if (!0){
		double h, m, s;
		acc_CPUtime += total;

		fid1.precision(0);
		fid1 << "          CPU-time[sec]  percentual\n";
		fid1 << "------------------------------------------------\n";
		convertSecToTime(t1,&h,&m,&s);
		fid1 << "elliptic   : " << fixed << h <<"(h)  "<< m <<"(m)  "<< s <<"(s) " << 100.0*(t1/total) <<"%\n";
		convertSecToTime(t2,&h,&m,&s);
		fid1 << "hyperbolic : " << h <<"(h)  "<< m <<"(m)  "<< s <<"(s) " << 100.0*(t2/total) <<"%\n";
		convertSecToTime(t1+t2,&h,&m,&s);
		fid1 << "ellip+hyper: " << h <<"(h)  "<< m <<"(m)  "<< s <<"(s)\n";
		convertSecToTime(acc_CPUtime,&h,&m,&s);
		fid1 << "accumulated: " << h <<"(h)  "<< m <<"(m)  "<< s <<"(s)\n\n";
		cout << "Accumulated Simulation time: " << h <<"(h)  "<< m <<"(m)  "<< s <<"(s)\n\n";
		fid1.precision(5);
		fid1 << "Step       : " << ++count  <<"\n";
		fid1 << "timeStep   : " << timeStep <<"\n";
		fid1 << fixed << "Sum. tSteps: " << accSimTime  <<"\n\n\n";

		char cString[256]; sprintf(cString,"%f %f %f %f\n",t1,t2,t1+t2,acc_CPUtime);
		string theString(cString);
		replaceAllOccurencesOnString(theString,1,".",",");
		fid2 << theString;
		//}
	}
	break;
	case CLOSELG:{
		if (!0){
			fid1.close();
			fid2.close();
		}
	}
	}
}

void STOP(){
	MPI_Barrier(MPI_COMM_WORLD); throw 1;
}

int printMatrixToFile(Mat& m,const char* filename){
	PetscViewer viewer;
	PetscViewerASCIIOpen(PETSC_COMM_WORLD,filename,&viewer);
	MatView(m,viewer);
	PetscViewerDestroy(viewer);
	return 0;
}

int printVectorToFile(Vec& v,const char* filename){
	PetscViewer viewer;
	PetscViewerASCIIOpen(PETSC_COMM_WORLD,filename,&viewer);
	VecView(v,viewer);
	PetscViewerDestroy(viewer);
	return 0;
}


double dot(const double *u, const double *v, int dim){
	double _dot = .0;
	for (int i=0;i<dim;i++){
		_dot += u[i]*v[i];
	}
	return _dot;
}

double norm_L2(const double *p, int dim){
	return sqrt( dot(p,p,dim) );
}

double sum(double* val, int size){
	double s = .0;
	for (int i=0; i<size; i++){
		s += val[i];
	}
	return s;
}

int P_size(){
	int size;
	MPI_Comm_size(PETSC_COMM_WORLD,&size);
	return size;
}

int P_pid(){
	int rank;
	MPI_Comm_rank(PETSC_COMM_WORLD,&rank);
	return rank;
}

void PrintForDebugging(const char* msg){
#ifdef __SEEKFORBUGS___
	PetscPrintf(PETSC_COMM_WORLD,msg);
#endif
}
